package com.file.parser;

import com.file.bo.AppTmriXszCar;
import com.file.bo.AppTmriXszDzxsz;
import com.file.bo.AppTmriXszJyhgbz;
import com.file.bo.ResponseData;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.jsoup.Jsoup;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * 行驶证xml解析
 *
 * @author anyspa
 */

@Slf4j
public class AppTmriXszXmlParser {

    public ResponseData<String> parseAppTmriXszXmlToJson(String daId, String filePath) {
        log.info("parseAppTmriXszXmlToJson started, daId:{}, filePath:{}", daId, filePath);
        String json;

        try {
            if (filePath.contains("tmri-xsz-car")) {
                AppTmriXszCar appTmriXszCar = parseAppTmriXszCarXml(filePath);
                json = JsonUtils.convertObjectToJson(appTmriXszCar);
            } else if (filePath.contains("tmri-xsz-jyhgbz")) {
                AppTmriXszJyhgbz appTmriXszJyhgbz = parseAppTmriXszJyhgbzXml(filePath);
                json = JsonUtils.convertObjectToJson(appTmriXszJyhgbz);
            } else if (filePath.contains("tmri-xsz-dzxsz")) {
                AppTmriXszDzxsz appTmriXszDzxsz = parseAppTmriXszDzxszHtml(filePath);
                json = JsonUtils.convertObjectToJson(appTmriXszDzxsz);
            } else {
                throw new RuntimeException("the file name is not supported");
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseAppTmriXszXmlToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(),
                    ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseAppTmriXszXmlToJson completed, daId:{}, filePath:{}", daId, filePath);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private AppTmriXszCar parseAppTmriXszCarXml(String filePath) throws DocumentException {
        AppTmriXszCar appTmriXszCar = new AppTmriXszCar();
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath));

        //app-tmri-xsz-car-0.xml
        String indexStr = filePath.substring(filePath.indexOf("-car-") + 5, filePath.indexOf(".xml"));

        Element numberPlateElement = (Element) document.selectNodes("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_hphm']").get(Integer.valueOf(indexStr));
        appTmriXszCar.setNumberPlate(numberPlateElement != null ? numberPlateElement.attributeValue("text").trim() : null);

        Element nameElement = (Element) document.selectNodes("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_syr']").get(Integer.valueOf(indexStr));
        appTmriXszCar.setName(nameElement != null ? nameElement.attributeValue("text").trim() : null);

        Element expiryDateOfInspectionElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_jyyxqz']");
        appTmriXszCar.setExpiryDateOfInspection(expiryDateOfInspectionElement != null ? expiryDateOfInspectionElement.attributeValue("text").trim() : null);

        Element motorVehicleStatusElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_state']");
        appTmriXszCar.setMotorVehicleStatus(motorVehicleStatusElement != null ? motorVehicleStatusElement.attributeValue("text").trim() : null);

        Element mortgageRegistrationStatusElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_dyzt']");
        appTmriXszCar.setMortgageRegistrationStatus(mortgageRegistrationStatusElement != null ? mortgageRegistrationStatusElement.attributeValue("text").trim() : null);

        Element registrationDateElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_zcdjrq']");
        appTmriXszCar.setRegistrationDate(registrationDateElement != null ? registrationDateElement.attributeValue("text").trim() : null);

        Element cellphoneNoElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_sjhm']");
        appTmriXszCar.setCellphoneNo(cellphoneNoElement != null ? cellphoneNoElement.attributeValue("text").trim() : null);

        Element endOfMandatoryRetirementPeriodElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_qzbfqz']");
        appTmriXszCar.setEndOfMandatoryRetirementPeriod(endOfMandatoryRetirementPeriodElement != null ? endOfMandatoryRetirementPeriodElement.attributeValue("text").trim() : null);

        Element compulsoryInsuranceExpiryDateElement = (Element) document.selectSingleNode("//android.widget.TextView[@resource-id='com.tmri.app.main:id/tv_jqxzzrq']");
        appTmriXszCar.setCompulsoryInsuranceExpiryDate(compulsoryInsuranceExpiryDateElement != null ? compulsoryInsuranceExpiryDateElement.attributeValue("text").trim() : null);

        List<Node> nodes = document.selectNodes("//android.widget.TextView");
        for (Node node : nodes) {
            String text = ((Element) node).attributeValue("text");
            if (StringUtils.isNotBlank(text) && text.trim().contains("被他人备案记录")) {
                appTmriXszCar.setRecordedByOthers("true");
            }
        }

        return appTmriXszCar;
    }

    private AppTmriXszJyhgbz parseAppTmriXszJyhgbzXml(String filePath) throws DocumentException {
        AppTmriXszJyhgbz appTmriXszJyhgbz = new AppTmriXszJyhgbz();
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath));
        Node node = document.selectSingleNode("//android.view.View[@text='检验有效期至']");
        if (node != null) {
            appTmriXszJyhgbz.setExpiryDateOfInspection(getNextNodeTextValue(document, "android.view.View", "检验有效期至"));
            appTmriXszJyhgbz.setNumberPlate(getNextNodeTextValue(document, "android.widget.TextView", "号牌号码"));
            appTmriXszJyhgbz.setPlateType(getNextNodeTextValue(document, "android.widget.TextView", "号牌种类"));
            appTmriXszJyhgbz.setVehicleIdentificationCode(getNextNodeTextValue(document, "android.widget.TextView", "车辆识别代号"));
            appTmriXszJyhgbz.setNatureOfUse(getNextNodeTextValue(document, "android.widget.TextView", "使用性质"));
            appTmriXszJyhgbz.setVehicleType(getNextNodeTextValue(document, "android.widget.TextView", "车辆类型"));
            appTmriXszJyhgbz.setInspectionAgency(getNextNodeTextValue(document, "android.widget.TextView", "检验机构"));
            appTmriXszJyhgbz.setConformityMarkNo(getNextNodeTextValue(document, "android.widget.TextView", "合格标志号"));
        } else {
            appTmriXszJyhgbz.setExpiryDateOfInspection(getNextNodeTextValue(document, "node", "检验有效期至"));
            appTmriXszJyhgbz.setNumberPlate(getNextNodeTextValue(document, "node", "号牌号码"));
            appTmriXszJyhgbz.setPlateType(getNextNodeTextValue(document, "node", "号牌种类"));
            appTmriXszJyhgbz.setVehicleIdentificationCode(getNextNodeTextValue(document, "node", "车辆识别代号"));
            appTmriXszJyhgbz.setNatureOfUse(getNextNodeTextValue(document, "node", "使用性质"));
            appTmriXszJyhgbz.setVehicleType(getNextNodeTextValue(document, "node", "车辆类型"));
            appTmriXszJyhgbz.setInspectionAgency(getNextNodeTextValue(document, "node", "检验机构"));
            appTmriXszJyhgbz.setConformityMarkNo(getNextNodeTextValue(document, "node", "合格标志号"));
        }
        return appTmriXszJyhgbz;
    }

    private AppTmriXszDzxsz parseAppTmriXszDzxszHtml(String filePath) {
        AppTmriXszDzxsz appTmriXszDzxsz = new AppTmriXszDzxsz();
        AppTmriXszDzxsz.MainPage mainPage = new AppTmriXszDzxsz.MainPage();
        AppTmriXszDzxsz.SupplementaryPage supplementaryPage = new AppTmriXszDzxsz.SupplementaryPage();
        appTmriXszDzxsz.setMainPage(mainPage);
        appTmriXszDzxsz.setSupplementaryPage(supplementaryPage);

        try {
            File input = new File(filePath);
            org.jsoup.nodes.Document doc = Jsoup.parse(input, "UTF-8");

            mainPage.setVehicleType(doc.select("div[name=cllx]").text());
            mainPage.setNumberPlate(doc.select("div[name=hphm]").text());
            mainPage.setUsageNature(doc.select("div[name=syxz]").text());
            mainPage.setStatus(doc.select(".ztStr").text());
            mainPage.setOwner(doc.select("div[name=syr]").text());
            mainPage.setBrandModel(doc.select("div[name=ppxh]").text());
            mainPage.setVehicleIdentificationNumber(doc.select("div[name=clsbdh]").text());
            mainPage.setEngineNumber(doc.select("div[name=fdjh]").text());
            mainPage.setRegistrationDate(doc.select("div[name=zcrq]").text());
            mainPage.setCertificateIssueDate(doc.select("div[name=fzrq]").text());
            mainPage.setInspectionValidityPeriod(doc.select("span[name=yxqz]").text());
            mainPage.setGenerationTime(doc.select("span[name=scsj]").text());
            mainPage.setCertificateCoreNumber(doc.select("div#zxbhDiv").text().replace("*", ""));
            
            supplementaryPage.setForcedScrapDate(doc.select("div[name=qzbfqz]").text());
            supplementaryPage.setBodyColor(doc.select("div[name=csys]").text());
            supplementaryPage.setEnergyType(doc.select("div[name=nyzl]").text());
            supplementaryPage.setRatedPassengerCapacity(doc.select("div[name=hdzk]").text());
            supplementaryPage.setDimensions(doc.select("div[name=wkcc]").text());
            supplementaryPage.setTotalMass(doc.select("div[name=zzl]").text());
            supplementaryPage.setCurbWeight(doc.select("div[name=zbzl]").text());
            supplementaryPage.setRatedLoadCapacity(doc.select("div[name=hdzzl]").text());
            supplementaryPage.setTowingCapacity(doc.select("div[name=zqyzl]").text());
            supplementaryPage.setAddress(doc.select("div[name=zz]").text());
            supplementaryPage.setIssuingAuthority(doc.select("div[name=fzjg]").text());
            supplementaryPage.setRemarks(doc.select("div[name=bz]").text());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return appTmriXszDzxsz;
    }


    private void parseNodes(Element node, AppTmriXszCar appTmriXszCar) {
        String resourceIdValue = node.attributeValue("resource-id");
        if (StringUtils.isNotBlank(resourceIdValue)) {
            switch (resourceIdValue) {//NOSONAR
                case "com.tmri.app.main:id/tv_hphm":
                    appTmriXszCar.setNumberPlate(node.attributeValue("text"));
                    break;
                case "com.tmri.app.main:id/tv_syr":
                    appTmriXszCar.setName(node.attributeValue("text"));
                    break;
                case "com.tmri.app.main:id/tv_jyyxqz":
                    appTmriXszCar.setExpiryDateOfInspection(node.attributeValue("text"));
                    break;
                case "com.tmri.app.main:id/tv_state":
                    appTmriXszCar.setMotorVehicleStatus(node.attributeValue("text").trim());
                    break;
                case "com.tmri.app.main:id/tv_sjhm":
                    appTmriXszCar.setCellphoneNo(node.attributeValue("text"));
                    break;
                case "com.tmri.app.main:id/tv_qzbfqz":
                    appTmriXszCar.setEndOfMandatoryRetirementPeriod(node.attributeValue("text"));
                    break;
            }
        }

        List<Element> listElement = node.elements();
        for (Element e : listElement) {
            this.parseNodes(e, appTmriXszCar);
        }
    }

    // 根据 text="xxx" 属性, 找到该属性所在节点的下一个兄弟节点的text属性的值
    private String getNextNodeTextValue(Document document, String nodeName, String text) {
        Node node = document.selectSingleNode("//" + nodeName + "[@text='" + text + "']");
        if (node != null) {
            List<Element> elements = node.getParent().elements();
            for (int i = 0; i < elements.size(); i++) {
                String textValue = elements.get(i).attributeValue("text");
                if (text.trim().equals(textValue.trim())) {
                    return elements.get(i + 1).attributeValue("text").trim();
                }
            }
        }
        throw new RuntimeException("xml file does not contain text='" + text + "' attribute");
    }

    //如果关键字段有任一字段为空，则解析失败
    private void checkKeyField(String daId, AppTmriXszCar appTmriXszCar) {
        log.info("checkKeyField started daId: {}", daId);

        if (StringUtils.isBlank(appTmriXszCar.getName())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszCar name is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszCar.getMotorVehicleStatus())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszCar motorVehicleStatus is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszCar.getNumberPlate())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszCar numberPlate is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszCar.getExpiryDateOfInspection())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszCar expiryDateOfInspection is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszCar.getRecordedByOthers())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszCar recordedByOthers is null");
            throw new RuntimeException();
        }

        log.info("checkKeyField completed daId: {}", daId);
    }

    //如果关键字段有任一字段为空，则解析失败
    private void checkKeyField(String daId, AppTmriXszJyhgbz appTmriXszJyhgbz) {
        log.info("checkKeyField started daId: {}", daId);

        if (StringUtils.isBlank(appTmriXszJyhgbz.getNumberPlate())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz numberPlate is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszJyhgbz.getPlateType())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz plateType is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszJyhgbz.getVehicleIdentificationCode())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz vehicleIdentificationCode is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszJyhgbz.getNatureOfUse())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz natureOfUse is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszJyhgbz.getVehicleType())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz vehicleType is null");
            throw new RuntimeException();
        }

        if (StringUtils.isBlank(appTmriXszJyhgbz.getExpiryDateOfInspection())) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "checkKeyField appTmriXszJyhgbz expiryDateOfInspection is null");
            throw new RuntimeException();
        }

        log.info("checkKeyField completed daId: {}", daId);
    }


    public static void main(String[] args) {
        AppTmriXszXmlParser appTmriXszXmlParser = new AppTmriXszXmlParser();
        String json = appTmriXszXmlParser.parseAppTmriXszXmlToJson("daId", "D:\\data\\file\\app-trmi-any\\20240716\\app-tmri-xsz-dzxsz-A8H8K8.html").getData();
        System.out.println(json);

        json = appTmriXszXmlParser.parseAppTmriXszXmlToJson("daId", "D:\\data\\file\\app-trmi-any\\20240716\\de1x1wwn1813043090075398144_f6b8c58509932e092d074c1c7ece253c_app-tmri-any_origins\\app-tmri-xsz-car-0.xml").getData();
        System.out.println(json);

//        json = appTmriXszXmlParser.parseAppTmriXszXmlToJson("daId", "D:\\data\\file\\app-trmi-any\\20240709\\zd20kldt18105874328862433nk_6ebde233c6987467abdaaafa1a9796a1_app-tmri-any_origins\\app-tmri-xsz-car-2.xml").getData();
//        System.out.println(json);
//
//        json = appTmriXszXmlParser.parseAppTmriXszXmlToJson("daId", "D:\\data\\file\\app-trmi-any\\20240709\\zd20kldt18105874328862433nk_6ebde233c6987467abdaaafa1a9796a1_app-tmri-any_origins\\app-tmri-xsz-car-3.xml").getData();
//        System.out.println(json);

//        json = appTmriXszXmlParser.parseAppTmriXszXmlToJson("daId", "D:\\data\\file\\app-trmi-any\\zdbae1qp1656628506328809472-app-tmri-xsz-car-0.xml").getData();
//        System.out.println(json);
    }
}
